/*
  Copyright © 2010  Vinícius dos Santos Oliveira

      This file is part of Touché.

      Touché is free software: you can redistribute it and/or modify
      it under the terms of the GNU Lesser General Public License as published
      by the Free Software Foundation, either version 3 of the License, or
      (at your option) any later version.

      This program is distributed in the hope that it will be useful,
      but WITHOUT ANY WARRANTY; without even the implied warranty of
      MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
      GNU Lesser General Public License for more details.

      You should have received a copy of the GNU Lesser General Public License
      along with this program.  If not, see <http://www.gnu.org/licenses/>.
  */

#include "scribbleelement.h"
#include <QGraphicsScene>
using namespace Touche;
#include <QColorDialog>
#include <QStateMachine>
#include <QPropertyAnimation>
#include <QParallelAnimationGroup>
#include <QGraphicsSvgItem>
#include "widgets/imageitem.h"
#include "widgets/slideritem.h"
#include <QDebug>
#include <QFile>

// class ScribbleItem

static const QPointF neutralPos(0., 0.);
const QImage ScribbleItem::nullImage(":/gfx/png/null_scribble.png");

ScribbleItem::ScribbleItem(const QImage &image, QGraphicsItem *parentItem) :
        QGraphicsItem(parentItem),
        m_image(nullImage)
{
    QPainter painter(&m_image);
    painter.drawImage(neutralPos, image);
}

QRectF ScribbleItem::boundingRect() const
{
    return QRectF(neutralPos, m_image.size());
}

void ScribbleItem::paint(QPainter *painter, const QStyleOptionGraphicsItem *, QWidget *)
{
    painter->drawImage(neutralPos, m_image);
}

void ScribbleItem::setImage(const QImage &image)
{
    m_image = nullImage;
    {
        QPainter painter(&m_image);
        painter.drawImage(neutralPos, image);
    }
    QGraphicsItem::update();
}

// class ScribbleElement

static const QString type("scribble");
static const QSize size(120, 120);
const QImage ScribbleElement::nullImage(":/gfx/png/null_image.png", "png");

ScribbleElement::ScribbleElement() :
        locked(false),
        image(nullImage),
        pen(QBrush(Qt::black), 2., Qt::SolidLine, Qt::RoundCap),
        eraserPen(QBrush(Qt::transparent), 16., Qt::SolidLine, Qt::RoundCap),
        m_item(new QGraphicsSvgItem(":/gfx/svg/item_draw.svg"))
{
}

ScribbleElement::~ScribbleElement()
{
    if(QFile::exists(fileName)){
        QFile::remove(fileName);
    }
}

const QString &ScribbleElement::type() const
{
    return ::type;
}

QRectF ScribbleElement::item(QGraphicsItem *parentItem) const
{
    m_item->setParentItem(parentItem);
    return m_item->boundingRect();
}

QVector<QString> ScribbleElement::menuOptions() const
{
    static const QVector<QString> defaultAction(1, "edit");
    if(locked){
        return QVector<QString>();
    }else{
        return defaultAction;
    }
}

void ScribbleElement::onMenuActived(const QString &option)
{
    if(option == "view"){
        // TODO
    }else{
        emit sceneRequest();
    }
}

QString ScribbleElement::save() const
{
    return QString();
}

static const QBrush background(QImage(":/gfx/png/scribble_background.png", "png"));

void ScribbleElement::onSceneReceived(QGraphicsScene *scene)
{
    scene->setBackgroundBrush(background);

    QAnimationGroup *majorAnimationGroup = new QParallelAnimationGroup();

    scribbleArea = new ScribbleAreaItem(&image);
    scribbleArea->setPos(404., -180.);
    scene->addItem(scribbleArea);

    QPropertyAnimation *animation = new QPropertyAnimation(scribbleArea, "pos");
    animation->setEndValue(QPointF(200., 12.));
    animation->setEasingCurve(QEasingCurve::InOutQuint);
    animation->setDuration(550);
    majorAnimationGroup->addAnimation(animation);

    SliderItem *slider = new SliderItem(":/gfx/svg/scribble_brush_slider.svg", ":/gfx/svg/scribble_brush_size.svg");
    slider->setPos(684.,130.);
    slider->setMinimum(1);
    slider->setMaximum(20);
    slider->setValue(2);
    scene->addItem(slider);

//    QGraphicsItem *showSize = new QGraphicsSvgItem(":/gfx/svg/scribble_brush_shower.svg");
//    scene->addItem(showSize);
//    showSize->setPos(676.,400.);

    connect(slider, SIGNAL(valueChanged(uint)), this, SLOT(onSizeChanged(uint)));

    menu[0] = new PushButtonItem(":/gfx/svg/button-ok.svg");
    menu[1] = new PushButtonItem(":/gfx/svg/edit-clear.svg");
    menu[2] =  new PushButtonItem(":/gfx/svg/pen.svg");
    menu[3] = new PushButtonItem(":/gfx/svg/eraser.svg");
    menu[4] = new PushButtonItem(":/gfx/svg/color-picker.svg");

    menu[0]->setHasBg(true);
    menu[1]->setHasBg(true);
    menu[2]->setHasBg(true);
    menu[3]->setHasBg(true);
    menu[4]->setHasBg(true);

    animation = new QPropertyAnimation(menu[0], "scale");
    menu[0]->setPos(643., 33.);
    menu[0]->setScale(0.);
    menu[1]->setTransformOriginPoint(32.9105, 32.9105);
    animation->setDuration(400);
    animation->setEndValue(1.);
    animation->setEasingCurve(QEasingCurve::OutBack);
    majorAnimationGroup->addAnimation(animation);
    scene->addItem(menu[0]);

    animation = new QPropertyAnimation(menu[1], "scale");
    menu[1]->setPos(43., 33.);
    menu[1]->setScale(0.);
    menu[1]->setTransformOriginPoint(32.9105, 32.9105);
    animation->setEasingCurve(QEasingCurve::OutBack);
    animation->setEndValue(1.);
    animation->setDuration(400);
    majorAnimationGroup->addAnimation(animation);

    scene->addItem(menu[1]);

    animation = new QPropertyAnimation(menu[2], "scale");
    menu[2]->setPos(43., 111.);
    menu[2]->setScale(0.);
    menu[2]->setTransformOriginPoint(32.9105, 32.9105);
    animation->setEasingCurve(QEasingCurve::OutBack);
    animation->setEndValue(1.);
    animation->setDuration(400);
    majorAnimationGroup->addAnimation(animation);
    menu[2]->setCheckable(true);
    menu[2]->setChecked(true);
    scene->addItem(menu[2]);

    animation = new QPropertyAnimation(menu[3], "scale");
    menu[3]->setPos(43., 189.);
    menu[3]->setScale(0.);
    menu[3]->setTransformOriginPoint(32.9105, 32.9105);
    animation->setEndValue(1.);
    animation->setEasingCurve(QEasingCurve::OutBack);
    animation->setDuration(400);
    majorAnimationGroup->addAnimation(animation);
    menu[3]->setCheckable(true);
    scene->addItem(menu[3]);

    animation = new QPropertyAnimation(menu[4], "scale");
    menu[4]->setPos(43., 267.);
    menu[4]->setScale(0.);
    menu[4]->setTransformOriginPoint(32.9105, 32.9105);
    animation->setEndValue(1.);
    animation->setEasingCurve(QEasingCurve::OutBack);
    animation->setDuration(400);
    majorAnimationGroup->addAnimation(animation);
    scene->addItem(menu[4]);
    majorAnimationGroup->start(QAbstractAnimation::DeleteWhenStopped);

    connect(menu[0], SIGNAL(clicked()), this, SLOT(onFinish()));
    connect(menu[1], SIGNAL(clicked()), scribbleArea, SLOT(clearImage()));
    connect(menu[1], SIGNAL(clicked()), this, SLOT(onPenButtonClicked()));
    connect(menu[2], SIGNAL(clicked()), this, SLOT(onPenButtonClicked()));
    connect(menu[3], SIGNAL(clicked()), this, SLOT(onEraserButtonClicked()));
    connect(menu[4], SIGNAL(clicked()), this, SLOT(onColorChoose()));
    connect(menu[4], SIGNAL(clicked()), this, SLOT(onPenButtonClicked()));
}

void ScribbleElement::onElementLocked(bool locked)
{
    this->locked = locked;
}

QString ScribbleElement::file()
{
    if(fileName.isEmpty()){
        fileName = "scribble_" + m_id + ".png";
        image.save(fileName);
    }
    return fileName;
}

void ScribbleElement::load(const QString &, const QString &file)
{
    if(QFile::exists(fileName)){
        QFile::remove(fileName);
    }
    fileName = file;
    m_null = false;

    {
        QImage normal(file, "png");
        image = normal.scaled(nullImage.size(), Qt::IgnoreAspectRatio, Qt::SmoothTransformation).convertToFormat(QImage::Format_ARGB32, Qt::ColorOnly);
    }
    if(ScribbleItem *item = dynamic_cast<ScribbleItem *>(m_item)){
        item->setImage(image);
    }else{
        QGraphicsItem *parent = m_item->parentItem();
        reinterpret_cast<QGraphicsObject *>(m_item)->deleteLater();
        m_item = new ScribbleItem(image.scaled(size, Qt::IgnoreAspectRatio, Qt::SmoothTransformation), parent);
    }
}

void ScribbleElement::onFinish()
{
    if(scribbleArea->isNull()){
        scribbleArea->deleteLater();
        scribbleArea = NULL;
        emit stageRequest();
    }else{
        m_null = false;
        if(ScribbleItem *sItem = dynamic_cast<ScribbleItem *>(m_item)){
            sItem->setImage(image.scaled(size, Qt::IgnoreAspectRatio, Qt::SmoothTransformation));
        }else{
            // it's a QGraphicsSvgItem
            QGraphicsItem *parent = m_item->parentItem();
            reinterpret_cast<QGraphicsObject *>(m_item)->deleteLater();
            m_item = new ScribbleItem(image.scaled(size, Qt::IgnoreAspectRatio, Qt::SmoothTransformation), parent);
        }
        scribbleArea->deleteLater();
        scribbleArea = NULL;
        emit contentsChanged();
        emit stageRequest();
    }
}

void ScribbleElement::onPenButtonClicked()
{
    scribbleArea->setPen(pen);
    scribbleArea->setCompositionMode();
    menu[2]->setChecked(true);
    menu[3]->setChecked(false);
}

void ScribbleElement::onEraserButtonClicked()
{
    scribbleArea->setPen(eraserPen);
    scribbleArea->setCompositionMode(QPainter::CompositionMode_SourceIn);
    menu[2]->setChecked(false);
    menu[3]->setChecked(true);
//    scribbleArea->setCursor(QCursor(QPixmap(), 16., 16.));
}

void ScribbleElement::onColorChoose()
{
    pen.setColor(QColorDialog::getColor(pen.color()));
    scribbleArea->setPen(pen);
}

void ScribbleElement::onSizeChanged(unsigned size)
{
    this->pen.setWidth(size);
    this->eraserPen.setWidth(size);

    if(menu[2]->isChecked())
        scribbleArea->setPen(this->pen);
    else
        scribbleArea->setPen(this->eraserPen);
}
